package run.halo.app.core.endpoint.theme;

import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
import static run.halo.app.extension.index.query.QueryFactory.equal;
import static run.halo.app.extension.index.query.QueryFactory.contains;
import static run.halo.app.extension.index.query.QueryFactory.or;

import io.swagger.v3.oas.annotations.enums.ParameterIn;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.fn.builders.operation.Builder;
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.content.Product;
import run.halo.app.core.extension.endpoint.CustomEndpoint;
import run.halo.app.extension.GroupVersion;
import run.halo.app.extension.ListOptions;
import run.halo.app.extension.ListResult;
import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.extension.router.SortableRequest;

/**
 * Endpoint for product query APIs.
 *
 * @author halo-product-management
 * @since 2.0.0
 */
@Component
@RequiredArgsConstructor
public class ProductQueryEndpoint implements CustomEndpoint {

    private final ReactiveExtensionClient client;

    @Override
    public RouterFunction<ServerResponse> endpoint() {
        final var tag = "ProductV1alpha1Public";
        return SpringdocRouteBuilder.route()
            .GET("products", this::listProducts,
                builder -> {
                    builder.operationId("queryProducts")
                        .description("Lists products.")
                        .tag(tag)
                        .response(responseBuilder()
                            .implementation(ListResult.generateGenericClass(Product.class))
                        );
                    ProductPublicQuery.buildParameters(builder);
                }
            )
            .GET("products/{name}", this::getByName,
                builder -> builder.operationId("queryProductByName")
                    .description("Gets product by name.")
                    .tag(tag)
                    .parameter(parameterBuilder()
                        .in(ParameterIn.PATH)
                        .name("name")
                        .description("Product name")
                        .required(true)
                    )
                    .response(responseBuilder()
                        .implementation(Product.class)
                    )
            )
            .build();
    }

    private Mono<ServerResponse> getByName(ServerRequest request) {
        String name = request.pathVariable("name");
        return client.get(Product.class, name)
            .flatMap(product -> ServerResponse.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(product)
            );
    }

    private Mono<ServerResponse> listProducts(ServerRequest request) {
        System.out.println("🎯 ProductQueryEndpoint.listProducts() 被调用!");
        System.out.println("📋 请求URI: " + request.uri());
        System.out.println("🔍 查询参数: " + request.queryParams());
        
        ProductPublicQuery query = new ProductPublicQuery(request.exchange());
        return client.listBy(Product.class, query.toListOptions(), query.toPageRequest())
            .doOnNext(result -> {
                System.out.println("✅ ProductQueryEndpoint 返回 " + result.getItems().size() + " 个产品");
            })
            .flatMap(result -> ServerResponse.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(result)
            );
    }

    public static class ProductPublicQuery extends SortableRequest {
        public ProductPublicQuery(ServerWebExchange exchange) {
            super(exchange);
        }

        @Override
        public ListOptions toListOptions() {
            var builder = ListOptions.builder(super.toListOptions());
            
            // 根据产品类型过滤 - 使用字段选择器而不是标签选择器
            Optional.ofNullable(queryParams.getFirst("productTypeRef"))
                .filter(StringUtils::hasText)
                .ifPresent(productTypeRef -> {
                    System.out.println("🎯 ProductQueryEndpoint: 应用productTypeRef过滤，值=" + productTypeRef);
                    builder.andQuery(equal("spec.productTypeRef", productTypeRef));
                });
            
            // 根据关键词搜索产品名称和描述
            Optional.ofNullable(queryParams.getFirst("keyword"))
                .filter(StringUtils::hasText)
                .ifPresent(keyword -> {
                    System.out.println("🔍 ProductQueryEndpoint: 应用关键词搜索，值=" + keyword);
                    builder.andQuery(or(
                        contains("spec.displayName", keyword),
                        contains("spec.description", keyword)
                    ));
                });
            
            var listOptions = builder.build();
            System.out.println("📋 ProductQueryEndpoint: 最终查询选项=" + listOptions);
            return listOptions;
        }

        public static void buildParameters(Builder builder) {
            SortableRequest.buildParameters(builder);
            // 添加productTypeRef参数文档
            builder.parameter(parameterBuilder()
                .in(ParameterIn.QUERY)
                .name("productTypeRef")
                .description("Filter products by product type reference")
                .implementation(String.class))
                .parameter(parameterBuilder()
                .in(ParameterIn.QUERY)
                .name("keyword")
                .description("Search keyword for product name and description")
                .implementation(String.class));
        }
    }

    @Override
    public GroupVersion groupVersion() {
        return PublicApiUtils.groupVersion(new Product());
    }
}